/***************************************************************************
 *   Copyright (C) 2005 by xihe						   *
 *   xihels@163.com							   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifndef _BUDDY_LIST_H_
#define _BUDDY_LIST_H_

#include <gtkmm/treeview.h>
#include <gtkmm/treestore.h>
#include <functional>
using std::unary_function;

// 刷新已显示的项
#define REFRESH_TREEITEM    1
// 显示未显示的项(默认)
#define ADD_TREEITEM	    2

#define TREE_ITEM_GROUP	    0
#define TREE_ITEM_CLUSTER   1
#define TREE_ITEM_BUDDY	    2
#define TREE_ITEM_USER	    3
#include "CycloneMenu.h"
#include "QQSession.h"
class MainWindow;
class BuddyList : public Gtk::TreeView {
    public:
	
	BuddyList(MainWindow& _parent);
	
	void refreshFriendsListStatus(const QQSession& session);
	void refreshFriendStatus(const QQSession& session,
	       	FriendInfo& friendinfo);
		
	void refreshFriendsList(const QQSession& session,
	       	int refreshtype);
	void refreshFriend(const QQSession& session, 
		FriendInfo& friendinfo);
	
	void refreshClustersList(const QQSession& session, 
		int refreshtype);
	void refreshCluster(const QQSession& session,
		ClusterInfo& clusterinfo);

	void refreshGroupsList(const QQSession& session, 
		int refreshtype); 

	void refreshSelfStatus(const QQSession& session);
	
	void removeUser(uint32_t uid);
	Gtk::TreeModel::iterator addUser(const QQSession& session);

	int getType(Gtk::TreeModel::iterator iter)
	{
	    return (*iter)[columns.type];
	}

	int getUid(Gtk::TreeModel::iterator iter)
	{
	    return (*iter)[columns.uid];
	}

	QQSession* getSession(Gtk::TreeModel::iterator iter)
	{
	    int tmp = (*iter)[columns.session];
	    return reinterpret_cast<QQSession*>(tmp);
	}

    private:
	bool on_button_press_event(GdkEventButton *ev);
	void on_cursor_changed();
    private:
	struct BuddyColumns : public Gtk::TreeModel::ColumnRecord {
	    friend struct compareBuddy;
	    BuddyColumns() 
	    {
		add(face);
		add(name); 
		add(uid);
		add(type);
		add(status);
		add(session);
	    }
	    Gtk::TreeModelColumn<Glib::RefPtr<Gdk::Pixbuf> >	face;
	    Gtk::TreeModelColumn<Glib::ustring>			name;

	    // 当列表项是 分组是，表示分组号
	    // 群分组的分组号设置为 CLUSTER_GROUP_NUM (-1);
	    Gtk::TreeModelColumn<int>			 uid;
	    // 列表项的类型
	    // 0为分组，1为群，2为好友
	    Gtk::TreeModelColumn<int>			 type;
	    Gtk::TreeModelColumn<int>			 status;
	    Gtk::TreeModelColumn<long>			 session;
	    // 好友所属的用户连接指针(QQSession*).
	};
    private:
	UserMenu   userMenu;
	GroupMenu  groupMenu;
	BuddyMenu  buddyMenu;

	BuddyColumns columns;
	Glib::RefPtr<Gtk::TreeStore> refTreeStore;

	MainWindow& parent;
    private:

	template <typename T>
	    void refreshFriendsList(
		    Gtk::TreeModel::iterator listhead,
		    const T& buddys,
		    int refreshtype,
		    int session = 0);


	Gtk::TreeModel::iterator getListIter(Gtk::TreeModel::Children children, int id);


	static bool isShow(const GroupInfo* groupinfo, int)
	{ return !groupinfo->isShowed(); }

	static bool isShow(const ClusterInfo* clusterinfo, int)
	{ return !clusterinfo->isShowed(); }

	static bool isShow(const FriendInfo* friendinfo, int group)
	{
	    return ((!friendinfo->isShowed()) && (friendinfo->getGroup() == group));
	}

	void setIter(const Gtk::TreeRow& row,
		GroupInfo& groupinfo, int session);
	void setIter(const Gtk::TreeRow& row,
		ClusterInfo& clusterinfo, int session);
	void setIter(const Gtk::TreeRow& row,
		FriendInfo& friendinfo, int session);

	struct RefreshFriendsStatus : public unary_function<Gtk::TreeRow, void> {
	    RefreshFriendsStatus(BuddyList& _wnd, const QQSession::Friends& _list) :
		wnd(_wnd), list(_list){}
	    void operator() (const Gtk::TreeRow& row);
	    BuddyList& wnd;
	    const QQSession::Friends& list;
	};

	template<typename T>
	    struct RefreshFriends : public unary_function<Gtk::TreeRow, void> {

		RefreshFriends(BuddyList& _wnd, const T& _list, int _session) :
		    wnd(_wnd), list(_list), session(_session) {}

		void operator () (const Gtk::TreeRow& row);
		BuddyList& wnd;
		const T&    list;
		int	    session;
	    };


	template<typename T>
	    struct AddFriends : public unary_function<typename T::value_type, void> {

		AddFriends(BuddyList& _wnd,
			Gtk::TreeModel::iterator& _iter, 
			int _session) :
		    wnd(_wnd), iter(_iter), session(_session)
		{ group = (*iter)[wnd.columns.uid];}

		void operator () (typename T::value_type value);
		BuddyList&		    wnd;
		Gtk::TreeModel::iterator&   iter;
		int			    session;
		int			    group;
	    };

	struct CompareBuddy : public binary_function<Gtk::TreeModel::Row, int, bool> {
	    explicit CompareBuddy(const BuddyColumns& _column):
		column(_column){}
	    bool operator ()(const Gtk::TreeRow& lhs, int var) const
	    {
		return lhs[column.uid] == var; 
	    }
	    const BuddyColumns& column;
	};

	// 排序函数
	int on_sort_compare(const Gtk::TreeModel::iterator& a, 
		const Gtk::TreeModel::iterator& b){
	    int result = (*a)[columns.status] - (*b)[columns.status];
	    if (0 == result)
		return (*a)[columns.uid] - (*b)[columns.uid];
	    return result;
	}

};



#endif // _BUDDY_LIST_H_

